package com.m4f.video.impl;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.logging.Logger;
import com.google.gdata.client.Query;
import com.google.gdata.client.youtube.YouTubeQuery;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.Category;
import com.google.gdata.data.media.mediarss.MediaCategory;
import com.google.gdata.data.media.mediarss.MediaDescription;
import com.google.gdata.data.media.mediarss.MediaKeywords;
import com.google.gdata.data.media.mediarss.MediaTitle;
import com.google.gdata.data.youtube.FormUploadToken;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.VideoFeed;
import com.google.gdata.data.youtube.YouTubeMediaGroup;
import com.google.gdata.data.youtube.YouTubeNamespace;
import com.google.gdata.data.youtube.YtPublicationState;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import com.m4f.video.ifc.IVideoService;

public class YoutubeVideoService implements IVideoService {

	private YouTubeService service = null;
	private static final Logger LOGGER = Logger
			.getLogger(YoutubeVideoService.class.getName());

	/**
	 * The default username.
	 */
	private static final String DEFAULT_USER = "default";
	/**FEEDS URLs*/
	private static final String DEFAULT_USER_FEED = "http://gdata.youtube.com/feeds/api/users/default/";
	private static final String UPLOAD_TOKEN_FEED = "http://gdata.youtube.com/action/GetUploadToken";
	private static final String USER_UPLOADS_FEED = "http://gdata.youtube.com/feeds/api/users/" + 
			DEFAULT_USER + "/uploads";
	
	/** The URL used to upload video*/
	private static final String VIDEO_UPLOAD_FEED = "http://uploads.gdata.youtube.com/feeds/api/users/"
			+ DEFAULT_USER + "/uploads";
	private static final String FAVORITE_FEED = "favorites";
	private static final String PLAYLISTS_FEED = "playlists";
	private static String developerID = "";
	private String developerKey;
	private String username;
	private String password;
	private YoutubeErrorHandler errorHandler;
	
	/**
	 * 
	 * @param developerID, youtube developer ID (susbribed email into youtube).
	 * @param developerKey, youtube developer KEY.
	 * @param username
	 * @param password
	 * @throws AuthenticationException
	 */
	public YoutubeVideoService(String developerID, String developerKey,
			String username, String password) throws AuthenticationException {
		this.developerID = developerID;
		this.developerKey = developerKey;
		this.username = username;
		this.password = password;
		this.errorHandler = new YoutubeErrorHandler();
	}

	public String getServiceVersion() throws AuthenticationException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		return this.service.getVersion().getVersionString();
	}

	
	@Override
	public FormUploadToken startVideoUpload(List<String> keywords, String title, String description,
			boolean isPrivate)throws ServiceException, IOException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		VideoEntry newEntry = new VideoEntry();
		YouTubeMediaGroup mg = newEntry.getOrCreateMediaGroup();
		mg.addCategory(new MediaCategory(YouTubeNamespace.CATEGORY_SCHEME,
				"Autos"));
		mg.setKeywords(new MediaKeywords());
		for (String keyword : keywords) {
			mg.getKeywords().addKeyword(keyword);
		}
		mg.setTitle(new MediaTitle());
		mg.setPrivate(isPrivate);
		mg.getTitle().setPlainTextContent(title);
		mg.setDescription(new MediaDescription());
		mg.getDescription().setPlainTextContent(description);
		FormUploadToken token = service.getFormUploadToken(new URL(
				UPLOAD_TOKEN_FEED), newEntry);
		return token;
	}
	
	@Override
	public void getUploadsVideos() throws MalformedURLException, IOException,
			ServiceException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		String feedUrl = USER_UPLOADS_FEED;
		VideoFeed videoFeed = service
				.getFeed(new URL(feedUrl), VideoFeed.class);
		for (VideoEntry entry : videoFeed.getEntries()) {
			LOGGER.info("Video id: " + entry.getMediaGroup().getVideoId());
			LOGGER.info("Video title: " + entry.getMediaGroup().getTitle().getPlainTextContent());
			if (entry.isDraft()) {
				LOGGER.info("Video is not live");
				YtPublicationState pubState = entry.getPublicationState();	
				if (pubState.getState() == YtPublicationState.State.PROCESSING) {
					LOGGER.info("Video is still being processed.");
				} else if (pubState.getState() == YtPublicationState.State.REJECTED) {
					System.out.print("Video has been rejected because: ");
					LOGGER.info(pubState.getDescription());
					System.out.print("For help visit: ");
					LOGGER.info(pubState.getHelpUrl());
				} else if (pubState.getState() == YtPublicationState.State.FAILED) {
					System.out.print("Video failed uploading because: ");
					LOGGER.info(pubState.getDescription());
					System.out.print("For help visit: ");
					LOGGER.info(pubState.getHelpUrl());
				}
			} else {
				LOGGER.info("Entry state: " + 
						entry.getPublicationState());
				
			}
		}
	}
	
	@Override
	public List<VideoEntry> search(String videoKey) throws IOException, ServiceException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		String pattern = videoKey;
		LOGGER.info("Pattern: " + pattern);
		YouTubeQuery query = new YouTubeQuery(new URL("http://gdata.youtube.com/feeds/api/videos"));
		//YouTubeQuery query = new YouTubeQuery(new URL(USER_UPLOADS_FEED));
		Query.CategoryFilter categoryFilter1 = new Query.CategoryFilter();
		categoryFilter1.addCategory(new Category(
				YouTubeNamespace.KEYWORD_SCHEME, pattern));
		query.addCategoryFilter(categoryFilter1);
		VideoFeed videoFeed = service.query(query, VideoFeed.class);
		LOGGER.info("VideoFeed size: " + videoFeed.getEntries().size());
		if (videoFeed.getEntries().size() == 0) {
			LOGGER.info("Video with key " + videoKey + " not exits.");
		}
		return videoFeed.getEntries();
	}

	
	@Override
	public boolean deleteVideo(String videoId) 
		throws AuthenticationException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		try {
			String videoEntryUrl = USER_UPLOADS_FEED + "/" + videoId;
			VideoEntry videoEntry = service.getEntry(new URL(videoEntryUrl),
					VideoEntry.class);
			videoEntry.delete();
			return true;
		} catch (Exception e) {
			LOGGER.severe("Imposble delete video with id: " + videoId
					+ " error " + e.getMessage());
			e.printStackTrace();
		}
		return false;
	}
	
	@Override
	public void updateVideoData(String videoId, 
			String title, String description, String location, 
			List<String> keywords) throws MalformedURLException, 
			IOException, ServiceException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		VideoEntry videoEntry = this.getVideoById(videoId);
		videoEntry.setLocation(location);
		YouTubeMediaGroup mg = videoEntry.getOrCreateMediaGroup();
		mg.getTitle().setPlainTextContent(title);
		mg.getDescription().setPlainTextContent(description);
		for(String keyword : keywords) {
			mg.getKeywords().addKeyword(keyword);
		}
		videoEntry.update();
	}
	
	@Override
	public VideoEntry getVideoById(String videoId)
			throws MalformedURLException, IOException, ServiceException {
		synchronized(this) {
			if(this.service==null) {
				this.service = new YouTubeService(developerID, developerKey);
				this.service.setUserCredentials(username, password);
			}
		}
		String videoEntryUrl = USER_UPLOADS_FEED + "/" + videoId;
		VideoEntry videoEntry = service.getEntry(new URL(videoEntryUrl),
				VideoEntry.class);
		return videoEntry;
	}
	
	@Override
	public String getErrorMessage(int errorCode) {
		return this.errorHandler.getMessage(errorCode);
	}
	
}